package cc.linker.steplink.crm.merchanth5.service;

import cc.linker.steplink.crm.commons.coupon.CouponCustomerInfo;
import cc.linker.steplink.crm.commons.coupon.CouponRequest;
import cc.linker.steplink.crm.commons.enums.IntegralEnums;
import cc.linker.steplink.crm.commons.utils.CalendarUtils;
import cc.linker.steplink.crm.merchanth5.dao.ScoreActiveCacheDao;
import cc.linker.steplink.crm.merchanth5.dao.SignDao;
import cc.linker.steplink.crm.merchanth5.dao.VipCustomerLogDao;
import cc.linker.steplink.crm.merchanth5.pojo.H5SignPo;
import cc.linker.steplink.crm.merchanth5.pojo.SignLogPo;
import cc.linker.steplink.crm.merchanth5.pojo.SignPo;
import cc.linker.steplink.crm.merchanth5.pojo.SignRewardLogPo;
import cc.linker.steplink.crm.merchanth5.pojo.coupon.CustomerCouponVo;
import cc.linker.steplink.crm.merchanth5.service.redis.SignCacheService;
import cc.linker.steplink.crm.response.GlobalException;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;


@Slf4j
@Service
public class SignService {

    private final SignDao signDao;
    private final SignCacheService signCacheService;
    private final CouponRequest couponRequest;
    private final CustomerIntegralService customerIntegralService;
    private final ScoreActiveCacheDao scoreActiveCacheDao;
    private final VipCustomerLogDao vipCustomerLogDao;
    private final StringRedisTemplate stringRedisTemplate;

    public SignService(SignDao signDao, SignCacheService signCacheService, CouponRequest couponRequest, CustomerIntegralService customerIntegralService, ScoreActiveCacheDao scoreActiveCacheDao, VipCustomerLogDao vipCustomerLogDao, StringRedisTemplate stringRedisTemplate) {
        this.signDao = signDao;
        this.signCacheService = signCacheService;
        this.couponRequest = couponRequest;
        this.customerIntegralService = customerIntegralService;
        this.scoreActiveCacheDao = scoreActiveCacheDao;
        this.vipCustomerLogDao = vipCustomerLogDao;
        this.stringRedisTemplate = stringRedisTemplate;
    }

    public void save(SignPo signpo) {
        SignPo info = signDao.getInfo(signpo);
        boolean isAdd = false;
        if (info == null || StringUtils.isEmpty(info.getOrgId())) {
            isAdd = true;
        }
        //            SignPo signpot = new SignPo();
        //            BeanUtils.copyProperties(signpo, signpot);
        //            signpot.setUpdateTime(info.getUpdateTime());
        //            signpot.setCycle(info.getCycle());
        signDao.save(signpo);
        signCacheService.setSignCache(signpo, isAdd);
        String keys = "marking:" + signpo.getOrgId();
        stringRedisTemplate.delete(keys);
    }

    public H5SignPo getSignInfo(H5SignPo h5SignPo) {

        SignPo signCycleByOrgId = signCacheService.getSignCycleByOrgId(h5SignPo.getOrgId());
        if (signCycleByOrgId != null && !StringUtils.isEmpty(signCycleByOrgId.getOrgId())) {
            CouponCustomerInfo customerInfo = CouponCustomerInfo
                    .builder()
                    .customerId(signCycleByOrgId.getOrgId())
                    .orgId(signCycleByOrgId.getOrgId())
                    .customerName("")
                    .customerPhone("")
                    .cover("")
                    .sourceUserId("")
                    .build();
            if (!StringUtils.isEmpty(signCycleByOrgId.getCoupons())) {
                ArrayList<Map<String, Object>> couponDetail = getCouponDetail(signCycleByOrgId.getCouponsArr(), signCycleByOrgId.getOrgId(), customerInfo);
                signCycleByOrgId.setCouponsArr(couponDetail);
            }
            if (!StringUtils.isEmpty(signCycleByOrgId.getSeriesReward())) {
                ArrayList<Map<String, Object>> temp = new ArrayList<>();
                for (Map<String, Object> seriesReward : signCycleByOrgId.getSeriesRewardArr()) {
                    if (null != seriesReward.get("coupons")) {
                        ArrayList couponList = JSON.parseObject(seriesReward.get("coupons").toString(), ArrayList.class);
                        if (couponList != null && couponList.size() > 0) {
                            ArrayList<Map<String, Object>> couponDetail = getCouponDetail(couponList, signCycleByOrgId.getOrgId(), customerInfo);
                            seriesReward.put("coupons", couponDetail);
                        }
                        temp.add(seriesReward);
                    }
                }
                signCycleByOrgId.setSeriesRewardArr(temp);
            }


            H5SignPo signpot = new H5SignPo();
            BeanUtils.copyProperties(signCycleByOrgId, signpot);
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
            String dateNowStr = sdf.format(new Date());
            h5SignPo.setDay(dateNowStr);
            int isSigned = signDao.getIsSigned(h5SignPo);
            signpot.setIsSgined(isSigned);
            String s = stringRedisTemplate.opsForValue().get("sign:remind_" + h5SignPo.getOrgId() + h5SignPo.getCustomerId());
            signpot.setIsRemind(StringUtils.isEmpty(s) ? 0 : 1);

            //获取相差天数
            int differDay = CalendarUtils.daysBetween(signpot.getUpdateTime(), new Date())+1;
            int cycle = Integer.parseInt(signpot.getCycle());
            if (cycle > 0 && differDay > cycle) {
                int add = differDay / cycle;
                Calendar calendar = new GregorianCalendar();
                calendar.setTime(signpot.getUpdateTime());
                calendar.add(Calendar.DATE, add*cycle);
                calendar.getTime();
                signpot.setUpdateTime(calendar.getTime());
            }
            return signpot;
        }
        return new H5SignPo();
    }

    public SignPo getInfo(SignPo signpo) {
        SignPo info = signDao.getInfo(signpo);
        if (info == null) {
            info = new SignPo();
        } else {
            CouponCustomerInfo customerInfo = CouponCustomerInfo
                    .builder()
                    .customerId(info.getOrgId())
                    .orgId(info.getOrgId())
                    .customerName("")
                    .customerPhone("")
                    .cover("")
                    .sourceUserId("")
                    .build();
            if (!StringUtils.isEmpty(info.getCoupons())) {
                ArrayList<Map<String, Object>> couponDetail = getCouponDetail(info.getCouponsArr(), info.getOrgId(), customerInfo);
                info.setCouponsArr(couponDetail);
            }
            if (!StringUtils.isEmpty(info.getSeriesReward())) {
                ArrayList<Map<String, Object>> temp = new ArrayList<>();
                for (Map<String, Object> seriesReward : info.getSeriesRewardArr()) {
                    if (null != seriesReward.get("coupons")) {
                        ArrayList couponList = JSON.parseObject(seriesReward.get("coupons").toString(), ArrayList.class);
                        if (couponList != null && couponList.size() > 0) {
                            ArrayList<Map<String, Object>> couponDetail = getCouponDetail(couponList, info.getOrgId(), customerInfo);
                            seriesReward.put("coupons", couponDetail);
                        }
                        temp.add(seriesReward);
                    }
                }
                info.setSeriesRewardArr(temp);
            }
        }
        return info;
    }

    protected ArrayList<Map<String, Object>> getCouponDetail(ArrayList<Map<String, Object>> couponList, String orgId, CouponCustomerInfo customerInfo) {
        for (int i = couponList.size() - 1; i >= 0; i--) {
            Map<String, Object> res = (Map) couponRequest.doRequest("coupon-detail", couponList.get(i), customerInfo);
            if (null == res || null == res.get("name")) {
                couponList.remove(i);
            } else {
                int maxPublishNum = 0;
                if (null != res.get("maxPublishNum")) {
                    maxPublishNum = Integer.parseInt(res.get("maxPublishNum").toString());
                }
                int publishNum = 0;
                if (null != res.get("publishNum")) {
                    publishNum = Integer.parseInt(res.get("publishNum").toString());
                }
                couponList.get(i).put("name", res.get("name"));
                couponList.get(i).put("inventory", maxPublishNum - publishNum);
            }
        }
        return couponList;
    }

    public Map<String, Object> getSignData(SignPo signpo, Integer pageIndex, Integer pageSize) {
        Map<String, Object> res = new HashMap<>();
        int allCustomerNum = signDao.getAllCustomerNum(signpo.getOrgId());
        int allNum = signDao.getNum(signpo.getOrgId());
        int preNum = Math.round((float) allNum / allCustomerNum);
        int sendNum = signDao.getSendNum(signpo.getOrgId());
        PageHelper.startPage(pageIndex, pageSize);
        List<Map<String, Object>> list = signDao.getLogList(signpo.getOrgId());
        res.put("list", new PageInfo<>(list));
        res.put("allCustomerNum", allCustomerNum);
        res.put("allNum", allNum);
        res.put("preNum", preNum);
        res.put("sendNum", sendNum);
        return res;
    }

    public List<Map<String, Object>> getSignSendLog(Map<String, Object> map) {
        return signDao.getSignSendLog(map);
    }


    /**
     * @Description：给用户赠送礼包
     * @DateTime：2021/1/20 9:47
     * @Params：
     * @Return：
     */
    public List<CustomerCouponVo> giveSignGift(String customerId, String orgId) {
        List<CustomerCouponVo> giveCoupons = new ArrayList<>();
        SignPo signPo = this.signCacheService.getSignCycleByOrgId(orgId);
        if (null == signPo.getStatus() || 0 == signPo.getStatus()) {
            return new ArrayList<>();
        }
        //这是每日签到赠送礼包
        List<CustomerCouponVo> everydayGifts = this.everydayGive(signPo, customerId, orgId, 1);
        if (everydayGifts.size() > 0) {
            giveCoupons.addAll(everydayGifts);
        }

        //region 进入循环连续签到赠送逻辑
        //循环天数
        int cycle = 99999;
        if(!StringUtils.isEmpty(signPo.getCycle()) && !"0".equals(signPo.getCycle())){
            cycle = Integer.parseInt(signPo.getCycle());
        }
        //循环初始时间
        Date initDay = signPo.getUpdateTime();
        if(cycle == 99999){
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            try {
                initDay = simpleDateFormat.parse("2021-01-20 00:00:00");
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }
        //获取相差天数
        int differDay = CalendarUtils.daysBetween(initDay, new Date());

        //如果剩余天数大于循环周期，则减去N个周期后已新周期来当前是这个周期的第几天
        if (differDay > cycle) {
            //新的循环里第几天签到
            int newCycleDay = differDay - (new Double(Math.floor(differDay / cycle)).intValue() * cycle);
            //新的周期里初始化的周期开始日期
            initDay = new Date((initDay.getTime() + 24 * 3600 * 1000 * (differDay - newCycleDay)));

            //当前真正的循环里第几天签到
            differDay = newCycleDay;
        }
        SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd");
        List<String> days = new ArrayList<>();

        Calendar c = Calendar.getInstance();
        c.setTime(initDay);
        days.add(f.format(c.getTime()));
        if (differDay > 0) {
            for (int i = 0; i <= differDay - 1; i++) {
                c.add(Calendar.DAY_OF_MONTH, 1);
                days.add(f.format(c.getTime()));
            }
        }

        //连续签到了几天
        int continuousSignNum = 0;
        //获取签到记录列表
        List<SignLogPo> signLogPoList = this.signDao.getCustomerSignLogByDate(customerId, days);
        if (signLogPoList != null && signLogPoList.size() > 0) {
            for (String d : days) {
                long count = signLogPoList.stream().filter(x -> f.format(x.getDay()).equals(d)).count();
                //代表当天他签到了
                if (count > 0) {
                    continuousSignNum++;
                } else {
                    continuousSignNum = 0;
                }
            }
        }
        //拿到当天的连续签到数量 去连续签到的设置中比对并赠送
        if (!StringUtils.isEmpty(signPo.getSeriesReward())) {
            for (Map<String, Object> x : signPo.getSeriesRewardArr()) {
                //遍历连续签到的规则，并判断是否规则满足，满足赠送东西。
                if (!StringUtils.isEmpty(x.get("day")) && continuousSignNum == Integer.parseInt(x.get("day").toString())) {
                    SignPo signPoNew = new SignPo();
                    signPoNew.setIfCoupons(StringUtils.isEmpty(x.get("ifCoupons")) ? 0 : Integer.parseInt(x.get("ifCoupons").toString()));
                    signPoNew.setIfScore(StringUtils.isEmpty(x.get("ifScore")) ? 0 : Integer.parseInt(x.get("ifScore").toString()));
                    signPoNew.setIfGrowth(StringUtils.isEmpty(x.get("ifGrowth")) ? 0 : Integer.parseInt(x.get("ifGrowth").toString()));
                    signPoNew.setCouponsArr(JSON.parseObject(JSON.toJSONString(x.get("coupons")), ArrayList.class));
                    signPoNew.setCoupons(JSON.toJSONString(x.get("coupons")));
                    signPoNew.setScore(StringUtils.isEmpty(x.get("score")) ? "0" : x.get("score").toString());
                    signPoNew.setGrowth(StringUtils.isEmpty(x.get("growth")) ? "0" : x.get("growth").toString());
                    List<CustomerCouponVo> continuousGifts = this.everydayGive(signPoNew, customerId, orgId, 2);
                    if (continuousGifts.size() > 0) {
                        giveCoupons.addAll(continuousGifts);
                    }
                }
            }
        }
        //endregion
        return giveCoupons;
    }

    /**
     * @DateTime：2021/1/20 11:00
     * @Params：
     * @Return： rewardType=1每日赠送
     * rewardType=2连签赠送
     */
    private List<CustomerCouponVo> everydayGive(SignPo signPo, String customerId, String orgId, int rewardType) {
        List<CustomerCouponVo> giveCoupons = new ArrayList<>();
        //积分是否赠送
        String tip = "签到赠送";
        String reward = "";
        if (signPo.getIfScore() == 1 && signPo.getScore() != null && Integer.parseInt(signPo.getScore()) > 0) {
            CustomerCouponVo integralModel = this.giveGifts(customerId, tip, IntegralEnums.customerScore.toString(), Integer.valueOf(signPo.getScore()), orgId);
            giveCoupons.add(integralModel);
            reward = reward + signPo.getScore() + "积分";
        }
        //成长值是否赠送
        if (signPo.getIfGrowth() == 1 && signPo.getGrowth() != null && Integer.parseInt(signPo.getGrowth()) > 0) {
            CustomerCouponVo growthModel = this.giveGifts(customerId, tip, IntegralEnums.customerGrowthScore.toString(), Integer.valueOf(signPo.getGrowth()), orgId);
            giveCoupons.add(growthModel);
            if (StringUtils.isEmpty(reward)) {
                reward = signPo.getGrowth() + "成长值";
            } else {
                reward = reward + "," + signPo.getGrowth() + "成长值";
            }
        }
        //判断是否赠送优惠券
        if (signPo.getIfCoupons() == 1 && signPo.getCoupons() != null && signPo.getCouponsArr() != null && signPo.getCouponsArr().size() > 0) {
            List<CustomerCouponVo> customerCouponVos = this.giveCoupons(signPo.getCouponsArr(), customerId, orgId);
            giveCoupons.addAll(customerCouponVos);

            if (customerCouponVos.size() > 0) {
                Map<String, Integer> map = new HashMap<>();
                for (CustomerCouponVo vo : customerCouponVos) {
                    int i = 1;
                    if (map.get(vo.getName()) != null) {
                        i = map.get(vo.getName()) + 1;
                    }
                    map.put(vo.getName(), i);
                }
                if(!map.isEmpty()){
                    for(String key : map.keySet()){
                        String rewardCoupon = key+"*"+map.get(key);
                        if (StringUtils.isEmpty(reward)) {
                            reward = rewardCoupon;
                        } else {
                            reward = reward + "," + rewardCoupon;
                        }
                    }
                }
            }
        }


        if (!StringUtils.isEmpty(reward)) {
            SignRewardLogPo signRewardLogPo = new SignRewardLogPo();
            signRewardLogPo.setCustomerId(customerId);
            signRewardLogPo.setOrgId(orgId);
            signRewardLogPo.setRewardType(rewardType);
            signRewardLogPo.setRewardDetail(reward);
            signDao.addSendLog(signRewardLogPo);
        }

        return giveCoupons;
    }

    /**
     * @Description：签到赠送
     * @DateTime：2021/1/20 10:59
     * @Params：
     * @Return：
     */
    private CustomerCouponVo giveGifts(String customerId, String tip, String type, Integer score, String orgId) {
        CustomerCouponVo customerCouponVo = CustomerCouponVo.builder().build();
        //调用积分服务赠送
        this.customerIntegralService.addIntegralCustomerLog(customerId, tip, type, score.toString(), type, orgId);

        if (IntegralEnums.customerScore.toString().equals(type)) {
            customerCouponVo.setType(4);
            customerCouponVo.setName(score + "积分");
            //动态中添加
            Map<String, Object> logParam = new HashMap<>();
            logParam.put("scoreLogId", UUID.randomUUID().toString());
            logParam.put("customerId", customerId);
            logParam.put("scoreValue", score);
            //14 签到赠送
            logParam.put("scoreType", 14);
            logParam.put("actionRemark", tip + score + "积分");
            logParam.put("sendWx", 1);
            this.scoreActiveCacheDao.addLog(logParam);
        } else {
            customerCouponVo.setType(5);
            customerCouponVo.setName(score + "成长值");
            Map<String, Object> log = new HashMap<String, Object>();
            log.put("logId", UUID.randomUUID().toString());
            log.put("customerId", customerId);
            log.put("growthValue", score);
            //14 签到赠送
            log.put("growthType", 14);
            log.put("actionRemark", tip + score + "成长值");
            vipCustomerLogDao.addGrowth(log);
        }
        return customerCouponVo;
    }

    /**
     * @Description：赠送优惠券
     * @DateTime：2021/1/20 11:07
     * @Params：
     * @Return：
     */
    private List<CustomerCouponVo> giveCoupons(ArrayList<Map<String, Object>> coupons, String customerId, String orgId) {
        List<CustomerCouponVo> giveCoupons = new ArrayList<>();
        Map<String, Object> param = new HashMap<>();
        param.put("couponList", coupons);
        CouponCustomerInfo customerInfo = CouponCustomerInfo
                .builder()
                .customerId(customerId)
                .orgId(orgId)
                .customerName("")
                .customerPhone("")
                .cover("")
                .sourceUserId("")
                .build();
        Object result = this.couponRequest.doRequest("give-coupons", param, customerInfo);
        if(null != result){
            List<String> consumptionIds = (List<String>) result;
            if (consumptionIds != null && consumptionIds.size() > 0) {
                param.put("consumptionIds", consumptionIds);
                result = this.couponRequest.doRequest("customer-coupon-list", param, customerInfo);
                List<JSONObject> customerCouponList = (List<JSONObject>) result;
                for (JSONObject couponVo : customerCouponList) {
                    giveCoupons.add(JSON.toJavaObject(couponVo, CustomerCouponVo.class));
                }
            }
        }
        return giveCoupons;
    }

    public Map<String, Object> getSignLog(String orgId, String customerId) {
        SignPo signPo = this.signCacheService.getSignCycleByOrgId(orgId);
        //循环天数
        int cycle = 99999;
        if(!StringUtils.isEmpty(signPo.getCycle()) && !"0".equals(signPo.getCycle())){
            cycle = Integer.parseInt(signPo.getCycle());
        }
        //循环初始时间
        Date initDay = signPo.getUpdateTime();
        if(null == initDay){
            initDay = new Date();
        }
        if(cycle == 99999){
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            try {
                initDay = simpleDateFormat.parse("2021-01-20 00:00:00");
            } catch (ParseException e) {
                e.printStackTrace();
            }
        }
        //获取相差天数
        int differDay = CalendarUtils.daysBetween(initDay, new Date());

        //如果剩余天数大于循环周期，则减去N个周期后已新周期来当前是这个周期的第几天
        if (differDay > cycle) {
            //新的循环里第几天签到
            int newCycleDay = differDay - (new Double(Math.floor(differDay / cycle)).intValue() * cycle);
            //新的周期里初始化的周期开始日期
            initDay = new Date((initDay.getTime() + 24 * 3600 * 1000 * (differDay - newCycleDay)));

            //当前真正的循环里第几天签到
            differDay = newCycleDay;
        }
        SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd");
        List<String> days = new ArrayList<>();
        H5SignPo h5SignPo = new H5SignPo();
        h5SignPo.setDay(f.format(new Date()));
        h5SignPo.setCustomerId(customerId);
        h5SignPo.setOrgId(orgId);
        int isSigned = signDao.getIsSigned(h5SignPo);
        differDay = differDay+isSigned;
        Calendar c = Calendar.getInstance();
        c.setTime(initDay);
        days.add(f.format(c.getTime()));
        if (differDay > 0) {
            for (int i = 0; i < differDay - 1; i++) {
                c.add(Calendar.DAY_OF_MONTH, 1);
                days.add(f.format(c.getTime()));
            }
        }

        //连续签到了几天
        int continuousSignNum = 0;
        //获取签到记录列表
        List<SignLogPo> signLogPoList = this.signDao.getCustomerSignLogByDate(customerId, days);
        if (signLogPoList != null && signLogPoList.size() > 0) {
            for (String d : days) {
                long count = signLogPoList.stream().filter(x -> f.format(x.getDay()).equals(d)).count();
                //代表当天他签到了
                if (count > 0) {
                    continuousSignNum++;
                } else {
                    continuousSignNum = 0;
                }
            }
        }
        List<SignLogPo> signLog = signDao.getSignLog(customerId);
        Map<String, Object> res = new HashMap<>();
        res.put("continuousSignNum", continuousSignNum);
        res.put("signLog", signLog);
        return res;
    }

    public List<CustomerCouponVo> doSign(String customerId, String orgId) {
        int todayLog = signDao.getTodaySignLog(customerId);
        if (todayLog > 0) {
            throw GlobalException.build("今日已签到");
        }
        SignLogPo signLogPo = new SignLogPo();
        signLogPo.setCustomerId(customerId);
        signLogPo.setOrgId(orgId);
        //判断是否是新签用户
        int isNew = signDao.getCustomerSignIsNew(signLogPo);
        signLogPo.setIsNew(isNew > 0 ? 0 : 1);
        //判断用户昨天有没有签到过
        int isSeries = signDao.getCustomerSignIsSeries(signLogPo);
        signLogPo.setIsSeries(isSeries > 0 ? 1 : 0);
        signDao.addSignLog(signLogPo);
        return giveSignGift(customerId, orgId);
    }

    public void setRemind(String orgId, String customerId) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        stringRedisTemplate.opsForValue().set("sign:remind_"+orgId+customerId,"1");
        stringRedisTemplate.expireAt("sign:remind_"+orgId+customerId,calendar.getTime());
    }
}
